//
// Created by guo on 24-8-29.
//

#ifndef TCPCLIENT_H
#define TCPCLIENT_H

#include <iostream>
#include <thread>
#include <boost/asio.hpp>
#include <boost/make_shared.hpp>
#include "struct.h"
#include "lockfree_queue.h"

using namespace boost::asio;

#define BUFFER_SIZE 1024

class TCPClient {
public:
    TCPClient(): _socket(_service){
        _data.resize(BUFFER_SIZE);
    }
    bool connect(const std::string& ip, uint16_t port){
        boost::system::error_code ec;
        _socket.connect(ip::tcp::endpoint(ip::address::from_string(ip),port),ec);
        if(ec){
            std::cout << ec.message() << std::endl;
            return false;
        }else{
            async_read();
            std::cout << _socket.local_endpoint().address().to_string() << ":" << _socket.local_endpoint().port() << std::endl;
            return true;
        }
    }

    void run(){
    }

    void poll_one(){
        _service.poll_one();
    }

    void send(const std::string& data){
        _socket.async_send(boost::asio::buffer(data,data.size()),
                           std::bind(&TCPClient::handle_send, this, std::placeholders::_1, std::placeholders::_2));
    }

    bool get_data(QueueDataPtr& queue_data){
        bool ret = _raw_data_queue.dequeue(queue_data);
        if(ret){
            return true;
        }else{
            return false;
        }
    }

protected:
    void handle_read(const boost::system::error_code& ec, size_t bytes_transferred){
        if(ec){
            std::cout << ec.message() << std::endl;
        }else{
            QueueDataPtr queue_data = boost::make_shared<QueueData>();
            queue_data->data = std::string(_data.data(), _data.size());
            _raw_data_queue.enqueue(queue_data);
        }
        async_read();
    }

    void handle_send(const boost::system::error_code& ec, size_t bytes_transferred){
        if(ec){
            std::cout << ec.message() << std::endl;
        }else{
            std::cout << "send to server: " << bytes_transferred << std::endl;
        }
    }

    void async_read(){
        _socket.async_read_some(boost::asio::buffer(_data),
                                std::bind(&TCPClient::handle_read, this, std::placeholders::_1, std::placeholders::_2));
    }
private:
    io_service _service;
    ip::tcp::socket _socket;
    std::vector<char> _data;
    LockFreeQueue<QueueDataPtr> _raw_data_queue;
};


#endif //TCPCLIENT_H
